package com.line.tools.util;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.*;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class WxUtils {
	static Charset CHARSET = Charset.forName("utf-8");
	static int BLOCK_SIZE = 32;
	private static Logger log = LoggerFactory.getLogger(WxUtils.class);

	public static String doGet(String url) throws Exception {
		String charset = "utf-8";
		URL localURL = new URL(url);
		URLConnection connection = openConnection(localURL);
		HttpURLConnection httpURLConnection = (HttpURLConnection) connection;

		httpURLConnection.setRequestProperty("Accept-Charset", charset);
		httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

		InputStream inputStream = null;
		InputStreamReader inputStreamReader = null;
		BufferedReader reader = null;
		StringBuffer resultBuffer = new StringBuffer();
		String tempLine = null;

		if (httpURLConnection.getResponseCode() >= 300) {
			throw new Exception("HTTP Request is not success, Response code is " + httpURLConnection.getResponseCode());
		}

		try {
			inputStream = httpURLConnection.getInputStream();
			inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
			reader = new BufferedReader(inputStreamReader);

			while ((tempLine = reader.readLine()) != null) {
				resultBuffer.append(tempLine);
			}

		} finally {

			if (reader != null) {
				reader.close();
			}

			if (inputStreamReader != null) {
				inputStreamReader.close();
			}

			if (inputStream != null) {
				inputStream.close();
			}

		}

		return resultBuffer.toString();
	}

	@SuppressWarnings("unused")
	private static URLConnection openConnection(URL localURL) throws IOException {
		String proxyHost = null;
		Integer proxyPort = null;
		URLConnection connection;
		if (proxyHost != null && proxyPort != null) {
			Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
			connection = localURL.openConnection(proxy);
		} else {
			connection = localURL.openConnection();
		}
		return connection;
	}

	/**
	 * * 获得对明文进行补位填充的字节. * * @param count 需要进行填充补位操作的明文字节个数 * @return 补齐用的字节数组
	 */
	static byte[] encode(int count) { // 计算需要填充的位数
		int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
		if (amountToPad == 0) {
			amountToPad = BLOCK_SIZE;
		} // 获得补位所用的字符
		char padChr = chr(amountToPad);
		String tmp = new String();
		for (int index = 0; index < amountToPad; index++) {
			tmp += padChr;
		}
		return tmp.getBytes(CHARSET);
	}

	/** * 删除解密后明文的补位字符 * * @param decrypted 解密后的明文 * @return 删除补位字符后的明文 */
	static byte[] decode(byte[] decrypted) {
		int pad = (int) decrypted[decrypted.length - 1];
		if (pad < 1 || pad > 32) {
			pad = 0;
		}
		return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
	}

	/** * 将数字转化成ASCII码对应的字符，用于对明文进行补码 * * @param a 需要转化的数字 * @return 转化得到的字符 */
	static char chr(int a) {
		byte target = (byte) (a & 0xFF);
		return (char) target;
	}

	/**
	 * * 对于官方加密数据（encryptData）解密说明如下： 加密数据解密算法 接口如果涉及敏感数据（如wx.getUserInfo当中的 * openId 和unionId ），接口的明文内容将不包含这些敏感数据。开发者如需要获取敏感数据，需要对接口返回的加密数据( * encryptedData )进行对称解密。 解密算法如下： 对称解密使用的算法为 AES-128-CBC，数据采用PKCS#7填充。 * 对称解密的目标密文为 Base64_Decode(encryptedData), 对称解密秘钥 aeskey = * Base64_Decode(session_key),
	 * aeskey 是16字节 对称解密算法初始向量 iv 会在数据接口中返回。 * * @Description (TODO这里用一句话描述这个方法的作用) * @param encryptedData * 加密内容 * @param sessionKey * 小程序登录sessionKey * @param iv * 解密算法初始向量 iv 会在数据接口中返回。 * @param encodingFormat * 编码格式默认UTF-8 * @return 返回解密后的字符串 * @throws Exception
	 */
	public static String decrypt(String encryptedData, String sessionKey, String iv, String encodingFormat) throws Exception {
		Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
		byte[] _encryptedData = Base64.decodeBase64(encryptedData);
		byte[] _sessionKey = Base64.decodeBase64(sessionKey);
		byte[] _iv = Base64.decodeBase64(iv);
		SecretKeySpec sKeySpec = new SecretKeySpec(_sessionKey, "AES");
		IvParameterSpec ivParameterSpec = new IvParameterSpec(_iv);
		cipher.init(Cipher.DECRYPT_MODE, sKeySpec, ivParameterSpec);
		byte[] result = cipher.doFinal(_encryptedData);
		String originalString = new String(result, "UTF-8");
		return originalString;
	}

	public static byte[] getwxacodeunlimit(String scene, int width, String accessToken) {
		RestTemplate rest = new RestTemplate();
		byte[] result = null;
		try {
			String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken;
			Map<String, Object> param = new HashMap<>();
			param.put("scene", scene);
			param.put("width", width);
			param.put("auto_color", false);
			Map<String, Object> line_color = new HashMap<>();
			line_color.put("r", 95);
			line_color.put("g", 202);
			line_color.put("b", 112);
			param.put("line_color", line_color);
			MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
			HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<Map<String, Object>>(param, headers);
			ResponseEntity<byte[]> entity = rest.exchange(url, HttpMethod.POST, requestEntity, byte[].class, new Object[0]);
			result = entity.getBody();

		} catch (Exception e) {
			log.error("获取二维码异常，异常信息：", e);
			return null;
		}
		return result;
	}
}
